package com.meatball.dji.common.mqtt

import com.meatball.dji.common.mqtt.properties.BasicProperties
import com.meatball.dji.common.mqtt.properties.InboundTopic
import com.meatball.dji.common.mqtt.router.MqttMessageRouter
import jakarta.annotation.PostConstruct
import org.eclipse.paho.client.mqttv3.MqttClient
import org.eclipse.paho.client.mqttv3.MqttConnectOptions
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component

/**
 * TODO mqtt 连接
 *
 * @property basicProperties 基础配置属性
 */
@Component
class IMqttClient(
    private val basicProperties: BasicProperties,
    private val inboundTopic: InboundTopic,
    private val mqttMessageRouter: MqttMessageRouter
) {
    companion object {
        val logger = LoggerFactory.getLogger(IMqttClient::class.java)
    }

    private var client: MqttClient? = null

    /**
     * TODO 保证初始化逻辑只执行一次
     *
     */
    @PostConstruct
    private fun init() {
        client = connect()
    }

    /**
     * TODO 初次启动后订阅topic
     *
     * @param mqttClient
     */
    fun subscribeToTopics(mqttClient: MqttClient) {
        inboundTopic.inboundTopics.split(",").forEach {
            mqttClient.subscribe(it.trim())
            logger.info("订阅 $it 成功。")
        }
    }

    /**
     * @TODO 连接MQTT代理服务器。
     *
     * @return 返回MQTT客户端实例。
     */
    fun connect() : MqttClient {
        val broker = "tcp://${basicProperties.host}:${basicProperties.port}"
        val persistence = MemoryPersistence()

        return client ?: run {
            val mqttClient = MqttClient(broker, basicProperties.clientId, persistence)

            // MQTT连接选项
            val connOpts = MqttConnectOptions().apply {
                userName = basicProperties.username
                password = basicProperties.password.toCharArray()
                isCleanSession = false
            }

            // 设置回调
            mqttClient.setCallback(PushCallback(mqttMessageRouter, mqttClient))

            // 建立连接
            logger.info("正在连接到代理服务器broker：$broker。")
            mqttClient.connect(connOpts)
            logger.info("连接成功。")
            subscribeToTopics(mqttClient)

            mqttClient // 返回新创建的客户端实例
        }
    }

    fun getClient(): MqttClient {
        return client ?: throw IllegalArgumentException("连接客户端失败")
    }
}